feat: add GitHub API rate limit indicator to monitor API usage#36
feat: add GitHub API rate limit indicator to monitor API usage#36Aarya-Chaudhari wants to merge 1 commit intoAOSSIE-Org:mainfrom
Conversation
WalkthroughA new RateLimitIndicator component is introduced that fetches GitHub API rate limit data on mount and displays it in a fixed-position UI. The component is integrated into the App component's JSX to show remaining requests, total limits, and reset time. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Hello @Zahnentferner I have implemented the GitHub API Rate Limit Indicator which displays the remaining API requests and reset time using the Please review the PR and let me know if any changes required |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/RateLimitIndicator.tsx`:
- Around line 31-50: The component RateLimitIndicator currently hardcodes
user-facing strings ("Loading API status...", "GitHub API Status", "Remaining",
"Reset"); replace these with i18n lookups by importing the app's translation
helper (e.g., useTranslation or t) and using keys like rateLimit.loading,
rateLimit.title, rateLimit.remaining, and rateLimit.reset in the JSX; add the
corresponding entries to the i18n resource files for all supported locales and
update the component to call the translation function where the literals are
used (including the strong title and the two <p> labels) so no user-visible text
remains hardcoded.
- Around line 12-29: The current useEffect fetchRateLimit runs only on mount so
remaining/reset go stale; update RateLimitIndicator by either subscribing to the
app's GitHub request layer (e.g., hook into the same client/event emitter) or
implement polling inside useEffect: move fetchRateLimit into a named async
function (fetchRateLimit) and call it on an interval via setInterval, storing
the timer and clearing it on cleanup, and continue to call setRateLimit with
data.rate.*; ensure useEffect returns a cleanup that clears the interval to
avoid leaks.
- Around line 15-31: The fetchRateLimit function leaves rateLimit null on HTTP
errors/unexpected payloads which makes the UI show "Loading API status..."
forever; update fetchRateLimit to check response.ok after the fetch, handle
non-OK statuses by calling setRateLimit with an explicit error/unavailable
sentinel (e.g., an object like {error: true, message: ...}) and also validate
the parsed payload before reading data.rate; ensure the component reads
rateLimit.error (or similar) to render an "API unavailable" or error state
instead of the loading message, and keep console.error for debugging inside the
catch branch.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 093a237b-8479-428e-ae1a-a222929dad12
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (2)
src/App.tsxsrc/RateLimitIndicator.tsx
| useEffect(() => { | ||
| async function fetchRateLimit() { | ||
| try { | ||
| const response = await fetch("https://api.github.com/rate_limit"); | ||
| const data = await response.json(); | ||
|
|
||
| setRateLimit({ | ||
| limit: data.rate.limit, | ||
| remaining: data.rate.remaining, | ||
| reset: data.rate.reset, | ||
| }); | ||
| } catch (error) { | ||
| console.error("Error fetching rate limit:", error); | ||
| } | ||
| } | ||
|
|
||
| fetchRateLimit(); | ||
| }, []); |
There was a problem hiding this comment.
Refresh the quota after GitHub API activity.
This effect runs only once on mount, so remaining and reset become stale as soon as the user makes more GitHub requests. That undercuts the goal of using this widget to monitor quota while exploring orgs. Please either wire it to the same GitHub request layer the app uses or poll/refetch on an interval.
♻️ Minimal polling-based fix
useEffect(() => {
+ let cancelled = false;
+
async function fetchRateLimit() {
try {
const response = await fetch("https://api.github.com/rate_limit");
const data = await response.json();
- setRateLimit({
- limit: data.rate.limit,
- remaining: data.rate.remaining,
- reset: data.rate.reset,
- });
+ if (!cancelled) {
+ setRateLimit({
+ limit: data.rate.limit,
+ remaining: data.rate.remaining,
+ reset: data.rate.reset,
+ });
+ }
} catch (error) {
console.error("Error fetching rate limit:", error);
}
}
fetchRateLimit();
+ const intervalId = window.setInterval(fetchRateLimit, 30000);
+
+ return () => {
+ cancelled = true;
+ window.clearInterval(intervalId);
+ };
}, []);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| useEffect(() => { | |
| async function fetchRateLimit() { | |
| try { | |
| const response = await fetch("https://api.github.com/rate_limit"); | |
| const data = await response.json(); | |
| setRateLimit({ | |
| limit: data.rate.limit, | |
| remaining: data.rate.remaining, | |
| reset: data.rate.reset, | |
| }); | |
| } catch (error) { | |
| console.error("Error fetching rate limit:", error); | |
| } | |
| } | |
| fetchRateLimit(); | |
| }, []); | |
| useEffect(() => { | |
| let cancelled = false; | |
| async function fetchRateLimit() { | |
| try { | |
| const response = await fetch("https://api.github.com/rate_limit"); | |
| const data = await response.json(); | |
| if (!cancelled) { | |
| setRateLimit({ | |
| limit: data.rate.limit, | |
| remaining: data.rate.remaining, | |
| reset: data.rate.reset, | |
| }); | |
| } | |
| } catch (error) { | |
| console.error("Error fetching rate limit:", error); | |
| } | |
| } | |
| fetchRateLimit(); | |
| const intervalId = window.setInterval(fetchRateLimit, 30000); | |
| return () => { | |
| cancelled = true; | |
| window.clearInterval(intervalId); | |
| }; | |
| }, []); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/RateLimitIndicator.tsx` around lines 12 - 29, The current useEffect
fetchRateLimit runs only on mount so remaining/reset go stale; update
RateLimitIndicator by either subscribing to the app's GitHub request layer
(e.g., hook into the same client/event emitter) or implement polling inside
useEffect: move fetchRateLimit into a named async function (fetchRateLimit) and
call it on an interval via setInterval, storing the timer and clearing it on
cleanup, and continue to call setRateLimit with data.rate.*; ensure useEffect
returns a cleanup that clears the interval to avoid leaks.
| const response = await fetch("https://api.github.com/rate_limit"); | ||
| const data = await response.json(); | ||
|
|
||
| setRateLimit({ | ||
| limit: data.rate.limit, | ||
| remaining: data.rate.remaining, | ||
| reset: data.rate.reset, | ||
| }); | ||
| } catch (error) { | ||
| console.error("Error fetching rate limit:", error); | ||
| } | ||
| } | ||
|
|
||
| fetchRateLimit(); | ||
| }, []); | ||
|
|
||
| if (!rateLimit) return <p>Loading API status...</p>; |
There was a problem hiding this comment.
Don't leave the widget stuck in loading on failed responses.
If GitHub returns 403/5xx or an unexpected payload, the catch path only logs and rateLimit stays null, so the UI keeps showing Loading API status... forever even though loading already finished. Check response.ok and render an explicit unavailable/error state.
🛠️ Suggested error-state handling
export default function RateLimitIndicator() {
const [rateLimit, setRateLimit] = useState<RateLimitData | null>(null);
+ const [status, setStatus] = useState<"loading" | "ready" | "error">("loading");
useEffect(() => {
async function fetchRateLimit() {
try {
const response = await fetch("https://api.github.com/rate_limit");
+ if (!response.ok) {
+ throw new Error(`GitHub rate limit request failed: ${response.status}`);
+ }
const data = await response.json();
setRateLimit({
limit: data.rate.limit,
remaining: data.rate.remaining,
reset: data.rate.reset,
});
+ setStatus("ready");
} catch (error) {
console.error("Error fetching rate limit:", error);
+ setStatus("error");
}
}
fetchRateLimit();
}, []);
- if (!rateLimit) return <p>Loading API status...</p>;
+ if (status === "loading") return <p>Loading API status...</p>;
+ if (status === "error" || !rateLimit) return <p>API status unavailable</p>;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/RateLimitIndicator.tsx` around lines 15 - 31, The fetchRateLimit function
leaves rateLimit null on HTTP errors/unexpected payloads which makes the UI show
"Loading API status..." forever; update fetchRateLimit to check response.ok
after the fetch, handle non-OK statuses by calling setRateLimit with an explicit
error/unavailable sentinel (e.g., an object like {error: true, message: ...})
and also validate the parsed payload before reading data.rate; ensure the
component reads rateLimit.error (or similar) to render an "API unavailable" or
error state instead of the loading message, and keep console.error for debugging
inside the catch branch.
| if (!rateLimit) return <p>Loading API status...</p>; | ||
|
|
||
| const resetTime = new Date(rateLimit.reset * 1000).toLocaleTimeString(); | ||
|
|
||
| return ( | ||
| <div | ||
| style={{ | ||
| position: "fixed", | ||
| bottom: "20px", | ||
| right: "20px", | ||
| background: "#1f2937", | ||
| padding: "12px", | ||
| borderRadius: "8px", | ||
| color: "white", | ||
| fontSize: "14px", | ||
| }} | ||
| > | ||
| <strong>GitHub API Status</strong> | ||
| <p>Remaining: {rateLimit.remaining} / {rateLimit.limit}</p> | ||
| <p>Reset: {resetTime}</p> |
There was a problem hiding this comment.
Externalize the new UI copy.
Loading API status..., GitHub API Status, Remaining, and Reset are hardcoded here. Please move them into the app's i18n resources before shipping.
As per coding guidelines, "Internationalization: User-visible strings should be externalized to resource files (i18n)".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/RateLimitIndicator.tsx` around lines 31 - 50, The component
RateLimitIndicator currently hardcodes user-facing strings ("Loading API
status...", "GitHub API Status", "Remaining", "Reset"); replace these with i18n
lookups by importing the app's translation helper (e.g., useTranslation or t)
and using keys like rateLimit.loading, rateLimit.title, rateLimit.remaining, and
rateLimit.reset in the JSX; add the corresponding entries to the i18n resource
files for all supported locales and update the component to call the translation
function where the literals are used (including the strong title and the two <p>
labels) so no user-visible text remains hardcoded.
Description
This PR adds a GitHub API Rate Limit Indicator to the OrgExplorer UI.
The indicator displays the remaining API requests, total limit, and reset time using the GitHub rate limit endpoint.
This helps users monitor API usage and avoid hitting GitHub's rate limits when exploring large organizations.
Changes Made
RateLimitIndicator.tsx/rate_limitApp.tsxWhy This Feature
Since OrgExplorer relies heavily on GitHub API calls, displaying the current API usage status improves transparency and helps prevent unexpected API request failures.
Screenshots/Recordings:
Additional Notes:
Checklist
We encourage contributors to use AI tools responsibly when creating Pull Requests. While AI can be a valuable aid, it is essential to ensure that your contributions meet the task requirements, build successfully, include relevant tests, and pass all linters. Submissions that do not meet these standards may be closed without warning to maintain the quality and integrity of the project. Please take the time to understand the changes you are proposing and their impact.
Summary by CodeRabbit